package com.example.http.demo.config;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.http.demo.dto.SaveApiKeyDTO;
import com.example.http.demo.dto.SaveRequestLogDTO;
import com.example.http.demo.dto.UpdateApiKeyDTO;
import com.example.http.demo.dto.UpdateRequestLogDTO;
import com.example.http.demo.mapper.TblRequestLogMapper;
import com.example.http.demo.model.TblApiKey;
import com.example.http.demo.model.TblRequestLog;
import com.example.http.demo.reponse.ApiKeyResponse;
import com.example.http.demo.reponse.HttpBaseResponse;
import com.example.http.demo.service.ApiKeyService;
import com.example.http.demo.utils.JsonUtil;
import com.google.common.base.Joiner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Configuration
public class RestTemplateConfigure {

    @Autowired
    private TblRequestLogMapper tblRequestLogMapper;

    //存放的是请求链路的请求id
    private static final ThreadLocal<Long> LOG_ID = new ThreadLocal<>();


    //存放的是请求路径
    private static final ThreadLocal<String> REQUEST_URI = new ThreadLocal<>();


    @Autowired
    private HttpDemoProperties httpDemoProperties;

    @Autowired
    private ApiKeyService apiKeyService;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //存放存的是要处理api_key的请求路径
        List<String> processApiKeyUrl = Arrays.asList(httpDemoProperties.getRequestBaseUrl() + httpDemoProperties.getDeveloperRegisterUrl(),
                httpDemoProperties.getRequestBaseUrl() + httpDemoProperties.getDeveloperLoginUrl(),
                httpDemoProperties.getRequestBaseUrl() + httpDemoProperties.getDeveloperUpdateKeyUrl());

        //拦截请求
        restTemplate.setErrorHandler(new ResponseErrorHandler() {


            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
                return true;
            }

            @Override
            public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
                System.out.println("开始处理错误...");
                final UpdateRequestLogDTO updateRequestLogDTO = new UpdateRequestLogDTO();
                Long id = LOG_ID.get();
                updateRequestLogDTO.setId(id);
                InputStream inputStream = clientHttpResponse.getBody();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] chars = new char[1];
                StringBuilder stringBuilder = new StringBuilder();
                int charRead = 0;
                while ((charRead = bufferedReader.read(chars)) != -1) {
                    stringBuilder.append(new String(chars));
                }
                updateRequestLogDTO.setResponseParam(stringBuilder.toString());
                String response = stringBuilder.toString();
                HttpBaseResponse baseResponse = JsonUtil.parseObject(response, HttpBaseResponse.class);
                updateRequestLogDTO.setResponseStatus(baseResponse.isOk() ? 1 : 0);
                updateRequestLogDTO.setResponseCode(baseResponse.getCode() + "");
                //lambdaUpdateWrapper
                LambdaUpdateWrapper<TblRequestLog> lambdaUpdateWrapper = new UpdateWrapper().lambda();
                lambdaUpdateWrapper.set(TblRequestLog::getResponseStatus, baseResponse.isOk() ? 1 : 0);
                lambdaUpdateWrapper.set(TblRequestLog::getResponseCode, baseResponse.getCode() + "");
                lambdaUpdateWrapper.set(TblRequestLog::getResponseParam,stringBuilder.toString());
                lambdaUpdateWrapper.eq(TblRequestLog::getId, id);
                int res = tblRequestLogMapper.update(null, lambdaUpdateWrapper);
                System.out.println("更新响应结果=" + res);
                LOG_ID.remove();
                //处理api_key更新的逻辑
                String url = REQUEST_URI.get();
                url = url.substring(0, url.lastIndexOf('?'));
                if (!baseResponse.isOk()) {
                    return;
                }
                for (String itemUrl : processApiKeyUrl) {
                    int endIndex = itemUrl.lastIndexOf('?');
                    if (endIndex > 0) {
                        itemUrl = itemUrl.substring(0, itemUrl.lastIndexOf('?'));
                    }
                    if (itemUrl.contains(url)) {
                        //当前的请求是需要刷新api_key
                        ApiKeyResponse apiKeyResponse = JsonUtil.parseObject(stringBuilder.toString(), ApiKeyResponse.class);
                        TblApiKey tblApiKey = apiKeyService.selectApiKey();
                        if (tblApiKey == null) {
                            //新增
                            final SaveApiKeyDTO apiKey = new SaveApiKeyDTO();
                            apiKey.setApiKey(apiKeyResponse.getResult() != null ? apiKeyResponse.getResult().getApiKey() : null);
                            apiKey.setExpireTime(new Date());
                            apiKey.setRefreshTime(new Date());
                            apiKeyService.saveApiKey(apiKey);
                        } else {
                            //更新
                            final UpdateApiKeyDTO updateApiKeyDTO = new UpdateApiKeyDTO();
                            updateApiKeyDTO.setApiKey(apiKeyResponse.getResult() != null ? apiKeyResponse.getResult().getApiKey() : null);
                            updateApiKeyDTO.setRefreshTime(new Date());
                            updateApiKeyDTO.setUpdateTime(new Date());
                            apiKeyService.updateApiKey(updateApiKeyDTO);
                        }
                    }
                }

            }

        });

        restTemplate.setInterceptors(Collections.singletonList(
                new ClientHttpRequestInterceptor() {
                    @Override
                    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
                        System.out.println("请求参数：" +
                                (bytes != null ? new String(bytes) : null)
                                + "，请求method=" + httpRequest.getMethod().name()
                                + "，请求路径=" + httpRequest.getURI());
                        //落入请求参数
                        final SaveRequestLogDTO saveRequestLogDTO = new SaveRequestLogDTO();
                        saveRequestLogDTO.setRequestBody(bytes != null ? new String(bytes) : null);
                        HttpHeaders headers = httpRequest.getHeaders();
                        TblRequestLog requestLog = new TblRequestLog();
                        if (headers != null) {
                            Set<Map.Entry<String, List<String>>> entries = headers.entrySet();
                            StringBuilder stringBuilder = new StringBuilder();
                            entries.forEach((k) -> {
                                String key = k.getKey();
                                //[1,2]-> 1,2
                                List<String> values = k.getValue();
                                stringBuilder.append(key).append(":").append(Joiner.on(",").join(values)).append(";");
                            });
                            saveRequestLogDTO.setRequestHeader(stringBuilder.toString());
                            requestLog.setRequestHeader(stringBuilder.toString());
                        }
                        saveRequestLogDTO.setRequestMethod(httpRequest.getMethod().name());
                        saveRequestLogDTO.setRequestUrl(httpRequest.getURI().toString());
                        saveRequestLogDTO.setCreateTime(new Date());
                        saveRequestLogDTO.setRequestTime(new Date());
                        saveRequestLogDTO.setCreateUser("system");
                        requestLog.setCreateTime(new Date());
                        requestLog.setRequestMethod(httpRequest.getMethod().name());
                        requestLog.setRequestBody(bytes != null ? new String(bytes) : null);
                        requestLog.setCreateUser("system");
                        requestLog.setRequestUrl(httpRequest.getURI().toString());
                        requestLog.setRequestTime(new Date());
                        requestLog.setIsDeleted(0);
                        int res = tblRequestLogMapper.insert(requestLog);
                        LOG_ID.set(requestLog.getId());
                        REQUEST_URI.set(httpRequest.getURI().toString());

                        return clientHttpRequestExecution.execute(httpRequest, bytes);
                    }
                }
        ));
        return restTemplate;
    }
}
